package org.onvivals.app.websocket;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.onvivals.app.ai.asr.NlpService;
import org.onvivals.app.ai.llm.LLMFactory;
import org.onvivals.app.mqtt.util.PlayUtil;
import org.onvivals.common.exception.BusinessException;
import org.onvivals.module.iot.entity.IotDevice;
import org.onvivals.module.iot.service.IIotDeviceService;
import org.onvivals.module.pms.entity.PmsRole;
import org.onvivals.module.pms.entity.PmsRoleIndividuality;
import org.onvivals.module.pms.service.IPmsRoleIndividualityService;
import org.onvivals.module.pms.service.IPmsRoleService;
import org.onvivals.module.ums.entity.UmsUser;
import org.onvivals.module.ums.entity.UmsUserRole;
import org.onvivals.module.ums.service.IUmsUserRoleService;
import org.onvivals.module.ums.service.IUmsUserService;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@ServerEndpoint(value = "/websocket/{deviceNum}")
@Component
public class WsServerEndpoint {

	private static final AtomicInteger onlineNum = new AtomicInteger();
	private static final ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();
	private static final ConcurrentHashMap<String, FunASRIntegration> asrIntegrationMap = new ConcurrentHashMap<>();

	private NlpService nlpService;

	private NlpService getService() {
		return SpringUtil.getBean(NlpService.class);
	}

	@OnOpen
	public void onOpen(Session session, @PathParam("deviceNum") String deviceNum) throws IOException {
		log.info("用户 {} 连接成功，当前在线人数: {}", deviceNum, onlineNum.get());
		IIotDeviceService iIotDeviceService = SpringUtil.getBean(IIotDeviceService.class);
		IotDevice iotDevice = iIotDeviceService.selectDeviceBySerialNumber(deviceNum);
		System.out.println(iotDevice);
		if (iotDevice != null) {
			sessionPools.put(deviceNum, session);
			onlineNum.incrementAndGet();
			this.nlpService = getService();
			this.nlpService.init(deviceNum);
//			FunASRIntegration funASRIntegration = new FunASRIntegration();
//			if (funASRIntegration.start(deviceNum)) {
//				asrIntegrationMap.put(deviceNum, funASRIntegration);
//			}
			log.info("用户 {} 加入 websocket，当前在线人数: {}", deviceNum, onlineNum.get());
		}
	}

	@OnClose
	public void onClose(@PathParam("deviceNum") String deviceNum) {
		sessionPools.remove(deviceNum);
		onlineNum.decrementAndGet();
		this.nlpService.close(deviceNum);
//		FunASRIntegration funASRIntegration = asrIntegrationMap.remove(deviceNum);
//		if (funASRIntegration != null) {
//			funASRIntegration.close(deviceNum);
//		}
		log.info("用户 {} 断开连接，当前在线人数: {}", deviceNum, onlineNum.get());
	}

	@OnMessage
	public void onMessage(String message, @PathParam("deviceNum") String deviceNum) {
		try {
			long startTime = System.currentTimeMillis();
			if (!JSONUtil.isTypeJSON(message)) {
				log.warn("收到非JSON格式消息: {}", message);
				return;
			}

			String responseText = this.nlpService.text(deviceNum);
			log.info("语音识别结果: {}, 耗时: {}ms", responseText, System.currentTimeMillis() - startTime);

			if (StrUtil.isNotEmpty(responseText)) {
				processDeviceMessage(deviceNum, responseText);
			} else {
				PlayUtil playUtil = SpringUtil.getBean(PlayUtil.class);
				log.info("未识别到语音内容");
				playUtil.play(deviceNum, "", "0", 99);
			}
		} catch (Exception e) {
			log.error("处理WebSocket消息失败", e);
		} finally {
			try {
				this.nlpService.close(deviceNum);
			} catch (Exception e) {
				log.error("关闭NLP服务失败", e);
			}
		}
	}

	public void processDeviceMessage(String deviceNum, String responseText) {
		IIotDeviceService iIotDeviceService = SpringUtil.getBean(IIotDeviceService.class);
		IotDevice iotDevice = iIotDeviceService.getOne(Wrappers.<IotDevice>lambdaQuery().eq(IotDevice::getSerialNumber, deviceNum));
		if (iotDevice == null) {
			log.warn("未找到对应设备信息: {}", deviceNum);
			return;
		}

		Long userId = iotDevice.getUserId();
		if (ObjectUtil.isEmpty(userId)) {
			log.warn("设备未绑定用户: {}", deviceNum);
			return;
		}

		IUmsUserService iUmsUserService = SpringUtil.getBean(IUmsUserService.class);
		UmsUser umsUser = iUmsUserService.getById(userId);

		// 检查用户会员状态
		if (ObjectUtil.isNotEmpty(umsUser)) {
			Date vipExpireTime = umsUser.getVipExpireTime();
			if (ObjectUtil.isNotEmpty(vipExpireTime) && vipExpireTime.before(new Date())) {
				PlayUtil playUtil = SpringUtil.getBean(PlayUtil.class);
				// 播放会员过期提示音
				playUtil.play(deviceNum, "http://101.126.138.204:9000/toy/toy/no_money.MP3", "0", 99);
				log.warn("用户会员已过期: {}", deviceNum);
				return;
			}
		}
		// 获取设备角色
		IPmsRoleService iPmsRoleService = SpringUtil.getBean(IPmsRoleService.class);
		PmsRole pmsRole = ObjectUtil.isNotEmpty(iotDevice.getRoleId()) ?
				iPmsRoleService.getById(iotDevice.getRoleId()) :
				iPmsRoleService.getOne(Wrappers.<PmsRole>lambdaQuery().eq(PmsRole::getIsDefault, true));
		if (pmsRole == null) {
			log.warn("未找到角色信息: {}", deviceNum);
			return;
		}
		log.info("角色 :{}", pmsRole.getName());

		// 获取角色个性化设置
		IPmsRoleIndividualityService iPmsRoleIndividualityService = SpringUtil.getBean(IPmsRoleIndividualityService.class);
		PmsRoleIndividuality roleIndividuality = iPmsRoleIndividualityService.getById(iotDevice.getIndividualityId());
		if (roleIndividuality != null) {
			String prompt = roleIndividuality.getPrompt();
			if (StrUtil.isNotEmpty(prompt) && umsUser != null) {
				prompt = replacePlaceholders(prompt, umsUser, pmsRole, userId);
				pmsRole.setPrompt(prompt);
			}
		}

		// 调用聊天逻辑
		LLMFactory.build(pmsRole).chat(responseText, deviceNum, deviceNum);
	}

	private String replacePlaceholders(String prompt, UmsUser umsUser, PmsRole pmsRole, Long userId) {
		if (StrUtil.isNotEmpty(umsUser.getNickname())) {
			prompt = prompt.replace("{{nickname}}", umsUser.getNickname());
		}
		if (StrUtil.isNotEmpty(umsUser.getGender())) {
			prompt = prompt.replace("{{sex}}", umsUser.getGender());
		}
		if (StrUtil.isNotEmpty(umsUser.getBirthday())) {
			prompt = prompt.replace("{{birthday}}", umsUser.getBirthday());
		}
		if (StrUtil.isNotEmpty(umsUser.getIntroduction())) {
			prompt = prompt.replace("{{Introduction}}", umsUser.getIntroduction());
		}

		IUmsUserRoleService iUmsUserRoleService = SpringUtil.getBean(IUmsUserRoleService.class);
		UmsUserRole userRole = iUmsUserRoleService.getOne(Wrappers.<UmsUserRole>lambdaQuery()
				.eq(UmsUserRole::getUserId, userId)
				.eq(UmsUserRole::getRoleId, pmsRole.getId()));
		if (ObjectUtil.isNotEmpty(userRole)) {
			prompt = prompt.replace("{{botname}}", userRole.getRoleName());
		}else {
			prompt = prompt.replace("{{botname}}", pmsRole.getName());
		}
		log.info("提示词: {}", prompt);
		return prompt;
	}


	@OnMessage
	public void onMessage(byte[] message, @PathParam("deviceNum") String deviceNum) {
//		FunASRIntegration funASRIntegration = asrIntegrationMap.get(deviceNum);
//		if (funASRIntegration != null) {
//			funASRIntegration.process(deviceNum, message);
//		}
		this.nlpService.speechTranslation(message, deviceNum);
	}

	@OnError
	public void onError(Session session, Throwable throwable) {
		log.error("WebSocket 错误: ", throwable);
	}
}
